package com.pic.mgt.scheduler;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.Trigger;

import com.pic.mgt.log.IgxLog;
import com.pic.mgt.syushin.SyushinScheduler;
import com.pic.mgt.utils.IgxCollectionUtils;
import com.pic.mgt.utils.LogUtils;

/**
 * 業務排程
 * @author 洪政緯
 *
 */
public class SchedulerImpl implements Scheduler {
	protected QuartzAutoJob quartzAutoJob;
	
	public void startScheduler() throws SchedulerException {
		try {
			this.quartzAutoJob.startAutoJob();
		} catch (ScheduleAutoJobException e) {
			throw new SchedulerException(
					"Start business scheduler failed.", e);
		}
	}
	
	public void haltScheduler() {
		this.quartzAutoJob.haltAutoJob();
	}
	
	public void shutdownScheduler() {
		this.quartzAutoJob.shutdownAutoJob();
	}
	
	public boolean isHalted() {
		return this.quartzAutoJob.isHalted();
	}
	
	public boolean isShutdown() {
		return this.quartzAutoJob.isShutdown();
	}
	
	public boolean isStarted() {
		return this.quartzAutoJob.isStarted();
	}
	
	@Override
	public void pauseJob(String jobName, String jobGroupName)
			throws SchedulerException {
		try {
			this.quartzAutoJob.pauseTrigger(jobName, jobGroupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
	}
	
	@Override
	public void resumeJob(String jobName, String jobGroupName)
			throws SchedulerException {
		try {
			this.quartzAutoJob.resumeTrigger(jobName, jobGroupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
	}
	
	@Override
	public void pauseJobGroup(String jobGroupName) throws SchedulerException {
		try {
			this.quartzAutoJob.pauseTriggerGroup(jobGroupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
	}
	
	@Override
	public void resumeJobGroup(String jobGroupName) throws SchedulerException {
		try {
			this.quartzAutoJob.resumeTriggerGroup(jobGroupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
	}
	
	@Override
	public void removeJob(String jobName, String groupName)
			throws SchedulerException {
		try {
			this.quartzAutoJob.removeScheduledJob(groupName, jobName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
		
		// ********************** Log **********************
		IgxLog.messageDetailsLog.info(this,
						"Removeing job completed. (job name:'{}' group name:'{}')",
						jobName, groupName);
		// ********************** Log **********************
	}
	
	@Override
	public void scheduleSimpleJob(Date scheduleTime, String jobName,
			String groupName, Class className, Map jobData) throws SchedulerException {
		try {
			this.quartzAutoJob.scheduleSimpleJob(scheduleTime, className, jobData, jobName, groupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
		
		// ********************** Log **********************
		IgxLog.messageDetailsLog.info(this,
						"Scheduled a simple job (job name:'{}' group name:'{}') with execution time '{}'.",
						jobName, groupName, scheduleTime);
		// ********************** Log **********************
	}
	
	@Override
	public void scheduleCronJob(String cronExpression, String jobName,
			String groupName, String jobDescription, Class className, Map jobData)
			throws SchedulerException {
		try {
			this.quartzAutoJob.scheduleCronJob(cronExpression, className, jobData, jobName, groupName, jobDescription);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
		
		// ********************** Log **********************
		IgxLog.messageDetailsLog.info(this,
						"Scheduled a cron job (job name:'{}' group name:'{}') with cron expression '{}'.",
						jobName, groupName, cronExpression);
		// ********************** Log **********************
	}
	
	@Override
	public void rescheduleCronJob(String cronExpression, String jobName,
			String groupName, String jobDescription) throws SchedulerException {
		try {
			this.quartzAutoJob.rescheduleCronJob(cronExpression, groupName, jobName, jobDescription);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
		
		// ********************** Log **********************
		IgxLog.messageDetailsLog.info(this,
						"Rescheduled a cron job (job name:'{}' group name:'{}').",
						jobName, groupName, cronExpression);
		// ********************** Log **********************
	}
	
	@Override
	public List<Map<String, Object>> getScheduleJobInfoByGroupName(
			String groupName) throws SchedulerException {
		List<Map<String, Object>> scheduleJobInfoList = new LinkedList<Map<String,Object>>();
		
		try {
			List<Trigger> triggerList =
				this.quartzAutoJob.getTriggersByGroupName(groupName);
			
			for (Trigger trigger : triggerList) {
				// 建立 trigger info map . 內容包含 trigger name, trigger group 和 trigger cron expression
				Map<String, Object> triggerInfoMap =
						IgxCollectionUtils.convertToMap(new String[] {
									TRIGGER_INFO_NAME, trigger.getName(),
									TRIGGER_INFO_GROUP, trigger.getGroup(),
									TRIGGER_INFO_CRONEXPRESSION, ((CronTrigger)trigger).getCronExpression(),
									TRIGGER_INFO_DESCRIPTION, trigger.getDescription()
						});
				
				scheduleJobInfoList.add(triggerInfoMap);
			}
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
		
		return scheduleJobInfoList;
	}
	
	@Override
	public int getJobStatus(String jobName, String groupName)
			throws SchedulerException {
		try {
			return this.quartzAutoJob.getTriggerState(jobName, groupName);
		} catch (ScheduleAutoJobException e) {
			// ********************** Log **********************
			LogUtils.error(this, IgxLog.messageLog, e);
			// ********************** Log **********************

			throw new SchedulerException(e.getMessage());
		}
	}
	
	@Override
	public String formatSchedules(List<Map<String, Object>> jobInfoMapList) throws SchedulerException {
		StringBuffer scheduleInfoStringBuf = new StringBuffer();
		scheduleInfoStringBuf.append("\r\n");
		scheduleInfoStringBuf.append(StringUtils.rightPad("Job Name", 15));
		scheduleInfoStringBuf.append(StringUtils.rightPad("Job Group", 20));
		scheduleInfoStringBuf.append(StringUtils.rightPad("Job Cron Expression", 20));
		scheduleInfoStringBuf.append(StringUtils.rightPad("Job Status", 20));
		scheduleInfoStringBuf.append("Job Description");
		scheduleInfoStringBuf.append("\r\n");
		scheduleInfoStringBuf.append("--------------------------------------------------------------------------------------------------------------------------\r\n");
		
		for (Map<String, Object> joInfoMap : jobInfoMapList) {
			String jobName = (String)joInfoMap.get(SyushinScheduler.TRIGGER_INFO_NAME);
			String jobGroup = (String)joInfoMap.get(SyushinScheduler.TRIGGER_INFO_GROUP);
			
			// 填入 Job Name
			scheduleInfoStringBuf.append(StringUtils.rightPad(jobName,15));
			// 填入 Job Group
			scheduleInfoStringBuf.append(StringUtils.rightPad(jobGroup,20));
			// 填入 Job Cronexpression
			scheduleInfoStringBuf.append(StringUtils.rightPad((String)joInfoMap.get(SyushinScheduler.TRIGGER_INFO_CRONEXPRESSION),20));
			
			// 填入 Job Status
			int triggerStat;
			try {
				triggerStat = this.quartzAutoJob.getTriggerState(jobName, jobGroup);
			} catch (ScheduleAutoJobException e) {
				// ********************** Log **********************
				LogUtils.error(this, IgxLog.messageLog, e);
				// ********************** Log **********************

				throw new SchedulerException(e.getMessage());
			}
			String jobStatusString = null;
			if (triggerStat == 4) { // STATE_BLOCKED
				jobStatusString = "Thread Blocking";
			}
			else if (triggerStat == 3) { // STATE_ERROR
				jobStatusString = "Schedule ERROR";
			}
			else if (triggerStat == 2) { // STATE_COMPLETE
				jobStatusString = "Executing Completed";
			}
			else if (triggerStat == 1) { // STATE_PAUSED
				jobStatusString = "Schedule Paused";
			}
			else if (triggerStat == 0) { // STATE_NORMAL
				jobStatusString = "Waiting";
			}
			else if (triggerStat == -1) { // STATE_NONE
				jobStatusString = "Schedule Not Existed";
			}
			scheduleInfoStringBuf.append(StringUtils.rightPad(jobStatusString,20));
			
			// 填入 Job Description
			scheduleInfoStringBuf.append((String)joInfoMap.get(SyushinScheduler.TRIGGER_INFO_DESCRIPTION));
			scheduleInfoStringBuf.append("\r\n");
		}
		
		return scheduleInfoStringBuf.toString();
	}
	
	// --- getter and setter ---
	
	public void setQuartzAutoJob(QuartzAutoJob quartzAutoJob) {
		this.quartzAutoJob = quartzAutoJob;
	}
}
